package com.zg.sso.service.impl;

import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zg.common.core.dao.sso.PushUnifiedAuthLog;
import com.zg.common.core.dao.sso.mapper.PushUnifiedAuthLogMapper;
import com.zg.sso.req.*;
import com.zg.sso.service.ZtService;
import com.zg.sso.util.DESUtil;
import com.zg.sso.util.RSAUtil;
import com.zg.sso.util.ZtRedisUtil;
import com.zg.sso.vo.SsoLoginVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.net.URLEncoder;
import java.util.Base64;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Service
@RequiredArgsConstructor
@Slf4j
public class ZtServiceImpl implements ZtService {

    @Value("${zt.rsaPublicKey}")
    private String rsaPublicKey;//公钥
    @Value("${zt.jiesuanSecret}")
    private String jiesuanSecret;
    @Value("${zt.indexUrl}")
    private String indexUrl;
    @Value("${zt.loginout}")
    private String loginoutUrl;
    @Value("${zt.pubKey}")
    private String pubKey;
    //基础服务地址
    @Value("${zt.baseApi}")
    private String baseApi;
    //用户管理服务地址
    @Value("${zt.remoteUser}")
    private String remoteUser;
    @Value("${zt.ssoMenuUrl}")
    private String ssoMenuUrl;

    private final ZtRedisUtil ztRedisUtil;
    private final RestTemplate restTemplate;
    private final PushUnifiedAuthLogMapper pushUnifiedAuthLogMapper;


    @Override
    public SsoLoginVo ssoLogin(SsoLoginReq param) {
        // 初始化返回对象
        SsoLoginVo ssoLoginVo = new SsoLoginVo();
        ssoLoginVo.setZtIndexUrl(indexUrl);

        String prefix = param.getPrefix();
        String ciphertext = param.getCiphertext();

        try {
            // 1. RSA非对称解密
            String decryptedText = RSAUtil.decrypt(ciphertext, rsaPublicKey);
            if (decryptedText == null) {
                log.error("RSA解密失败，密文可能不正确");
                return ssoLoginVo;
            }
            log.debug("RSA解密结果: {}", decryptedText);

            // 2. DES对称解密
            String desDecrypted = DESUtil.hutoolDecrypt(decryptedText, jiesuanSecret);
            if (desDecrypted == null) {
                log.error("DES解密失败");
                return ssoLoginVo;
            }
            log.debug("DES解密结果: {}", desDecrypted);

            // 3. 生成统一认证中心原始token
            String accessToken = prefix + "." + desDecrypted;
            log.debug("生成统一认证中心原始token: {}", accessToken);

            // 4. 从Redis获取用户信息
            String userInfo = ztRedisUtil.get("online:user:" + accessToken);
            if (StringUtils.isBlank(userInfo)) {
                log.error("Redis中未找到用户信息，token可能已失效");
                return ssoLoginVo;
            }

            // 5. 解析用户信息
            return processUserInfo(userInfo, accessToken, ssoLoginVo);

        } catch (Exception e) {
            log.error("统一认证登录过程发生异常", e);
            return ssoLoginVo;
        }
    }

    /**
     * 处理用户信息并生成登录结果
     *
     * @param userInfo Redis中存储的用户信息
     * @param accessToken 中台access token
     * @param ssoLoginVo 返回结果对象
     * @return 处理后的登录信息
     */
    private SsoLoginVo processUserInfo(String userInfo, String accessToken, SsoLoginVo ssoLoginVo) {
        try {
            JSONObject jsonObject = JSONObject.parseObject(userInfo);
            JSONArray authSysList = jsonObject.getJSONArray("authSysList");
            String loginId = jsonObject.getString("loginId");

            log.debug("用户ID: {}, 权限系统列表大小: {}", loginId, authSysList.size());

            // 遍历权限系统列表，查找结算系统权限
            for (int i = 0; i < authSysList.size(); i++) {
                JSONObject authSystem = authSysList.getJSONObject(i);
                String systemCode = authSystem.getString("sys");
                String authValue = authSystem.getString("auth");

                // 检查是否有结算系统权限
                if ("1".equals(authValue) &&
                        ("jiesuan_in".equals(systemCode) || "jiesuan_out".equals(systemCode))) {

                    // 设置中台令牌
                    ssoLoginVo.setZtAccessToken(accessToken);

                    // TODO: 获取当前系统token，这里需要实现真实的token获取逻辑
                    // 目前只是设置了一个固定值用于演示
                    ssoLoginVo.setToken(generateSystemToken(loginId, systemCode));

                    return ssoLoginVo;
                }
            }

            // 未找到有效的结算系统权限
            log.warn("用户 {} 没有结算系统访问权限", loginId);
            return ssoLoginVo;

        } catch (Exception e) {
            log.error("处理用户信息异常", e);
            return ssoLoginVo;
        }
    }

    /**
     * 生成系统token - 实际实现应替换此方法
     *
     * @param loginId 用户ID
     * @param systemCode 系统代码
     * @return 系统token
     */
    private String generateSystemToken(String loginId, String systemCode) {
        // TODO: 实现真实的token生成逻辑
        return "token";
    }

    @Override
    public String ssoLogout(SsoLogoutReq param) {
        try {
            String accessToken = param.getAccessToken();

            // 构建登出URL
            String url = loginoutUrl + "?access_token=" + accessToken + "&toUrl=";
            log.info("loginoutUrl===== {}", loginoutUrl);
            log.info("请求access_token的url是 {}", url);

            // 发送GET请求
            String forObject = restTemplate.getForObject(url, String.class);
            return forObject;
        } catch (Exception e) {
            log.error("登出过程发生异常", e);
            return "登出失败：" + e.getMessage();
        }
    }

    @Override
    public String ssoRefreshToken(SsoRefreshTokenReq param) {
        try {
            String key = "online:user:" + param.getAccessToken();
            String userInfo = ztRedisUtil.get(key);
            if(StringUtils.isNotBlank(userInfo)){
                ztRedisUtil.expire(key, 1800);
                return "延时成功";
            }
        }catch (Exception e){
            log.error("【统一认证-刷新token】出现异常",e);
            e.printStackTrace();
        }
        return "延时失败";
    }

    @Override
    public String syncUserInfo(SsoSyncUserInfoReq param) {
        String response = "";
        try {
            // 设置headers
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            // 构建请求参数
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("system", "jiesuan_in");
            map.put("operateType", 1);
            map.put("loginId", param.getUsername());

            // 加密密码
            RSA rsa = new RSA(null, pubKey);
            String encryptPwd = rsa.encryptBase64(param.getPwd(), KeyType.PublicKey);
            map.put("userPwd", encryptPwd);
            map.put("nickName", param.getNickName());
            map.put("orgId", param.getOrgId());

            // 请求体处理
            String paramJson = JSONObject.toJSONString(param);
            String encodedContent = Base64.getEncoder().encodeToString(paramJson.getBytes());

            Map<String, String> requestBody = new LinkedHashMap<>();
            requestBody.put("secretContent", encodedContent);

            // 发送请求
            HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<ObjectNode> responseEntity = restTemplate.postForEntity(
                    baseApi + remoteUser, requestEntity, ObjectNode.class);

            // 处理响应
            ObjectMapper objectMapper = new ObjectMapper();
            response = objectMapper.writeValueAsString(responseEntity.getBody());
            log.info("同步用户信息成功，用户：{}，响应：{}", param.getUsername(), response);

            return response;
        } catch (JsonProcessingException e) {
            log.error("处理JSON响应失败，用户：{}", param.getUsername(), e);
            response = "处理响应失败: " + e.getMessage();
            throw new RuntimeException("同步用户信息失败", e);
        } catch (Exception e) {
            log.error("同步用户信息异常，用户：{}", param.getUsername(), e);
            response = "同步用户信息异常: " + e.getMessage();
            throw new RuntimeException("同步用户信息失败", e);
        } finally {
            addPushUnifiedAuthLog(JSONUtil.toJsonStr(param), response, "1");
        }
    }

    private void addPushUnifiedAuthLog(String reqMsg, String rspMsg, String type) {
        try {
            PushUnifiedAuthLog pushUnifiedAuthLog = new PushUnifiedAuthLog();
            pushUnifiedAuthLog.setReqMsg(reqMsg);
            pushUnifiedAuthLog.setRspMsg(rspMsg);
            pushUnifiedAuthLog.setType(type);
            pushUnifiedAuthLogMapper.insert(pushUnifiedAuthLog);
            log.debug("记录统一认证推送日志成功，类型：{}", type);
        } catch (Exception e) {
            log.error("记录统一认证推送日志失败", e);
        }
    }

    @Override
    public String getOtherSystemLoginUrl(SsoGetOtherSystemLoginUrlReq param) {
        return restTemplate.getForObject(ssoMenuUrl + "?ztAccessToken=" + param.getZtAccessToken() + "&system=" + param.getSystem(),String.class);
    }
}
